package com.github.defense.plugin.gray.decision;


import com.github.defense.plugin.gray.holder.SpringContextHolder;
import com.github.defense.plugin.gray.decision.factory.GrayDecisionFactory;
import com.github.defense.plugin.gray.decision.predicate.DecisionDefinition;
import com.github.defense.plugin.gray.decision.predicate.PolicyDefinition;
import com.github.defense.plugin.gray.utils.ConfigurationUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.convert.ConversionService;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.validation.Validator;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @Author: lettger
 * @Date: 2021/6/8 6:33 下午
 */
@Slf4j
public class DefaultGrayDecisionResolver implements GrayDecisionResolver {


    private Map<String, GrayDecisionFactory> decisions = new HashMap<>();
    private SpelExpressionParser parser = new SpelExpressionParser();
    private ConversionService conversionService;
    private Validator validator;

    public DefaultGrayDecisionResolver(List<GrayDecisionFactory> decisionFactories, ConversionService conversionService, Validator validator) {
        this.conversionService = conversionService;
        this.validator = validator;
        decisionFactories.stream().forEach(factory -> {
            String key = factory.name();
            if (this.decisions.containsKey(key)) {
                log.warn("A GrayDecisionFactory named {} already exists, class:{} It will be overwritten.", key, this.decisions.get(key));
            }
            this.decisions.put(key, factory);
        });
    }

    @Override
    public GrayDecisionFactory getFactory(String name) {
        return decisions.get(name);
    }

    @Override
    public PolicyDefinition getPolicyDefinition(DecisionDefinition definition) {
        GrayDecisionFactory factory = getFactory(definition.getName());
        if (Objects.nonNull(factory)) {
            GrayDecision grayDecision = null;
            try {
                grayDecision = factory.apply(config -> {
                    Map<String, Object> properties = ConfigurationUtils.normalize(definition.getInfos(), parser, SpringContextHolder.getApplicationContext());
                    ConfigurationUtils.bind(config, properties, "", "", validator, conversionService);
                });
            } catch (Exception e) {
                log.error("======构造灰度断言工厂失败", e);
            }
            if (Objects.nonNull(grayDecision)) {
                return new PolicyDefinition(grayDecision, definition.getInstance());
            }
        }
        return null;
    }
}
